using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
using System.ComponentModel;
using System.Globalization;

namespace ResourceBlender_Express {
    /// <summary>
    /// The main window
    /// </summary>
    public partial class WinMain : Window {
        /// <summary>
        /// Initializes a new <see cref="WinMain"/> and sets up command bindings.
        /// </summary>
        public WinMain() {
            InitializeComponent();
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.ViewApplications, ViewApplications));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.ViewResourcesPrompt, ViewResourcesPrompt));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.GenerateResources, (s, e) => { new WinGenerate().Show(); }));

            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, e) => { Close(); }));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.Import, Import));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.Export, Export));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.ShowOptions, ShowOptionsHandler));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.ShowAbout, (s, e) => { new WinAbout().ShowDialog(); }));

            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.EditDefaultLanguage, EditDefaultLanguage));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.EditAllLanguages, EditAllLanguages));

            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.Edit, EditApplication, CanExecuteEditApplication));
            this.CommandBindings.Add(new CommandBinding(ResourceBlenderCommands.Delete, DeleteApplication, CanExecuteDeleteApplication));
        }

        #region Command Handlers
        /// <summary>
        /// Shows a window for managing applications
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ViewApplications(object sender, RoutedEventArgs e) {
            WinApplications dlg = new WinApplications();
            dlg.ShowDialog();
            RefreshSummary();
        }

        /// <summary>
        /// Shows a prompt to select an application, bundles and languages.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ViewResourcesPrompt(object sender, RoutedEventArgs e) {
            WinResourcesGridPrompt dlg = new WinResourcesGridPrompt();
            dlg.ShowDialog();
            if(dlg.DialogResult == true) {
                ViewResources(dlg.SelectedApplication, dlg.SelectedBundles, dlg.SelectedLanguages);
                RefreshSummary();
            }
        }

        /// <summary>
        /// Shows the import dialog.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Import(object sender, ExecutedRoutedEventArgs e) {
            WinImport dlg = new WinImport((Constants.DataType)Enum.Parse(typeof(Constants.DataType), e.Parameter.ToString(), true));
            if(dlg.ShowDialog() == true) {
                RefreshSummary();
            }
        }

        /// <summary>
        /// Shows the import dialog.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Export(object sender, ExecutedRoutedEventArgs e) {
            WinExport dlg = new WinExport((Constants.DataType)Enum.Parse(typeof(Constants.DataType), e.Parameter.ToString(), true));
            dlg.ShowDialog();
        }

        /// <summary>
        /// Shows the options dialog, then reloads settings.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void ShowOptionsHandler(object sender, RoutedEventArgs e) {
            WinOptions dlg = new WinOptions();
            dlg.ShowDialog();
            Properties.Settings.Default.Reload();
            RefreshSummary();
        }

        /// <summary>
        /// Determines whether the edit application command can be executed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExecuteEditApplication(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = lstApps != null && lstApps.SelectedItem != null;
        }

        /// <summary>
        /// Shows a window to edit an application.
        /// </summary>
        private void EditApplication(object sender, RoutedEventArgs e) {
            if(lstApps.SelectedValue == null)
                return;
            RBApplication originalApp = lstApps.SelectedValue as RBApplication;
            WinAddApplication dlg = new WinAddApplication(originalApp.Clone());
            if(dlg.ShowDialog() == true) {
                RefreshSummary();
            }
        }

        /// <summary>
        /// Determines whether the delete application command can be executed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanExecuteDeleteApplication(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = lstApps != null && lstApps.SelectedItem != null;
        }

        /// <summary>
        /// Deletes an application after the user has confirmed.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void DeleteApplication(object sender, ExecutedRoutedEventArgs e) {
            if(lstApps.SelectedValue == null)
                return;
            RBApplication app = lstApps.SelectedValue as RBApplication;
            if(DialogBox.Show(this, string.Format("Are you sure you want to delete the application '{0}'?{1}{1} All bundles and elements contained within this application will also be deleted. Translations, will be not be deleted.", app.DisplayName, Environment.NewLine), "Confirm Delete", DialogBox.DialogBoxType.YesNo, DialogBox.DialogBoxIcon.Question) == DialogBox.DialogBoxButton.Yes) {
                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += (s, dwe) => {
                    dwe.Result = WinApplications.DeleteApplication(app);
                };
                worker.RunWorkerCompleted += (s, rwe) => {
                    SetStatus(null);
                    if(rwe.Result != null) {
                        DialogBox.Show(this, rwe.Result.ToString(), "Database Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                    }
                    RefreshSummary();
                };
                SetStatus("Deleting application...");
                worker.RunWorkerAsync();
            }
        }
        #endregion

        /// <summary>
        /// Checks whether this is the first time the application has been run and shows a setup wizard installer if necessary.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            if(Properties.Settings.Default.FirstRun) {
                WinInstaller dlg = new WinInstaller();
                dlg.ShowDialog();
                if(dlg.DialogResult != true) { // setup not completed
                    Close();
                }
            }
            RefreshSummary();
        }

        #region Summary
        private void RefreshSummary() {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (s, dwe) => {
                Database db = null;
                try {
                    db = new Database();
                    db.OpenConnection();
                    dwe.Result = db.LoadApplications(true);
                } catch(Exception ex) {
                    dwe.Result = "Error #454: Could not connect to database - " + ex.Message;
                } finally {
                    try {
                        db.CloseConnection();
                    } catch { }
                }
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                SetStatus(null);
                if(rwe.Result is string) {
                    DialogBox.Show(this, rwe.Result.ToString(), "Error", DialogBox.DialogBoxType.OK, DialogBox.DialogBoxIcon.Error);
                } else {
                    List<RBApplication> applications = rwe.Result as List<RBApplication>;
                    if(applications.Count > 0) {
                        tbcSummary.SelectedIndex = 0;
                        lstApps.Items.Clear();
                        foreach(RBApplication app in applications) {
                            TextBlock txtName = new TextBlock();
                            lstApps.Items.Add(app);
                        }
                    } else {
                        tbcSummary.SelectedIndex = 1;
                    }
                }
            };
            SetStatus("Loading application summary...");
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Edits the default language in the selected application.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void EditDefaultLanguage(object sender, ExecutedRoutedEventArgs e) {
            RBApplication selectedApp = e.Parameter as RBApplication;
            if(selectedApp == null) {
                return;
            }
            ObservableSortedDictionary<string, string> languages = new ObservableSortedDictionary<string, string>(new Comparers.DictionaryValueComparer(), new Comparers.StringEqualityComparer());
            string englishName;
            try {
                englishName = CultureInfo.GetCultureInfo(selectedApp.DefaultLanguage).EnglishName;
            } catch {
                englishName = selectedApp.DefaultLanguage;
            }
            languages.Add(selectedApp.DefaultLanguage, englishName);
            if(languages.Count == 0) {
                DialogBox.ShowAlert(this, "At least one language and one bundle must be added before editing resources.", "Error");
            } else {
                ViewResources(selectedApp, selectedApp.Bundles, languages);
            }
        }

        /// <summary>
        /// Edits all languages in the selected application.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void EditAllLanguages(object sender, ExecutedRoutedEventArgs e) {
            RBApplication selectedApp = e.Parameter as RBApplication;
            if(selectedApp == null) {
                return;
            }
            ObservableSortedDictionary<string, string> languages = new ObservableSortedDictionary<string, string>(new Comparers.DictionaryValueComparer(), new Comparers.StringEqualityComparer());
            foreach(string code in selectedApp.Languages) {
                string englishName;
                try {
                    englishName = CultureInfo.GetCultureInfo(code).EnglishName;
                } catch {
                    englishName = code;
                }
                languages.Add(code, englishName);
            }
            if(languages.Count == 0) {
                DialogBox.ShowAlert(this, "At least one language and one bundle must be added before editing resources.", "Error");
            } else {
                ViewResources(selectedApp, selectedApp.Bundles, languages);
            }
        }
        #endregion

        /// <summary>
        /// Sets the text on the status message (null hides the statusbar and label).
        /// </summary>
        /// <param name="message">The message.</param>
        private void SetStatus(string message) {
            if(message == null) {
                prgStatus.Visibility = Visibility.Hidden;
                lblStatus.Visibility = Visibility.Hidden;
            } else {
                prgStatus.Visibility = Visibility.Visible;
                lblStatus.Visibility = Visibility.Visible;
                lblStatus.Content = message;
            }
        }

        /// <summary>
        /// Shows a window to view/edit resources for a selected application.
        /// </summary>
        /// <param name="app">The app.</param>
        /// <param name="selectedBundles">The selected bundles.</param>
        /// <param name="selectedLanguages">The selected languages.</param>
        private void ViewResources(RBApplication app, ObservableSortedDictionary<string, string> selectedBundles, ObservableSortedDictionary<string, string> selectedLanguages) {
            WinResourcesGrid dlg = new WinResourcesGrid(app, selectedBundles, selectedLanguages);
            dlg.ShowDialog();
        }
    }
}
